home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
DEMON
/
RISCOS2
/
TCP_131S.ARC
/
c
/
nntpcli
< prev
next >
Wrap
Text File
|
1994-03-10
|
31KB
|
1,354 lines
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include "kernel.h"
#include "global.h"
#include "timer.h"
#include "cmdparse.h"
#include "netuser.h"
#include "nntp.h"
#include "smtp.h"
#include "domain.h"
#include "misc.h"
#include "tcp.h"
#include "mbuf.h"
#include "arc.h"
#include "Terminal.h"
#include "flex.h"
#include "os.h"
#include "swis.h"
#include "Reader.h"
#define NNTPMAXLEN 512
#define BATCH_MAX 16
#define ID_LEN 28
#define NN_CMD 0
#define NN_DAT 1
#define NN_RDY 2
#define NN_OPEN 1
#define NN_NEWG 2
#define NN_NEWN 3
#define NN_GETN 4
#define NN_BYNUM 5
#define NN_SELG 6
#define NN_GNUM 7
#define NN_NEXT_STAGE 8
#define NN_POST 9
#define NN_PREARTSEND_STAGE 10
#define NN_POSTARTSEND_STAGE 11
#define NN_QUIT 12
static struct nntpservers {
struct timer nntpcli_t;
char *name;
char *abbr;
char *temp;
int lowtime, hightime; /* for connect window */
struct nntpservers *next;
struct tcb *tcb; /* tcp task control buffer */
int32 ipdest; /* address of forwarding system */
char state; /* state machine placeholder */
char stage; /* another state machine placeholder */
char buf[LINELEN]; /* Input buffer */
char cnt; /* Length of input buffer */
FILE *input1;
FILE *input0;
FILE *output;
FILE *id_file;
BOOL RS_Hist;
int dup_method;
int batch;
char now[20];
char date[20];
char hour[20];
long file_len;
int msg_tot;
char goodrcpt; /* are any of the rcpt ok */
char cts; /* clear to send state indication */
int rcpts; /* number of unacked rcpt commands */
struct list *errlog;
char (*got_table)[ID_LEN];
int lastread;
struct directory *topost;
long rnewspos;
Terminal *window;
};
struct directory
{
struct directory *next;
char *name;
};
#define NULLNNTP (struct nntpservers *)NULL
struct nntpservers *Nntpservers = NULLNNTP;
static void nntptick(void *);
static void make_got_table(int, void *);
static int doadds(int, char **);
static int dobatch(int, char **);
static int dodirect(int, char **);
static int dodrops(int, char **);
static int dodups(int, char **);
static int dofudge(int, char **);
static int dokicks(int, char **);
static int dolists(int, char **);
static int dostop(int, char **);
static int donntptrace(int, char **);
static void quit(struct nntpservers *, BOOL);
static void nntp_rec(struct tcb *, int16);
static void nntp_cts(struct tcb *, int16);
static void nntp_state(struct tcb *, char, char);
static void sendit(struct nntpservers *, char *, ...);
extern int lport; /* local port placeholder */
static int nntptrace = 0; /* used for trace level */
static char quitcmd[] = "QUIT\r\n";
static char *duptab[] = { "auto", "ReaderS", "history" };
static int dup_method = 0;
static int fudge = 0;
static int batch = 4;
static BOOL direct = FALSE;
struct cmds nntpcmds[] = {
"addserver", doadds, 4, "nntp addserver <name> <time> <abbr>", NULLCHAR,
"batch", dobatch, 1, "nntp batch <n>", NULLCHAR,
"direct", dodirect, 1, "nntp direct <on|off>", NULLCHAR,
"dropserver", dodrops, 2, "nntp dropserver <name|abbr>", NULLCHAR,
"duplicates", dodups, 1, "nntp duplicates [<auto|readers|history>]", NULLCHAR,
"fudge", dofudge, 1, "nntp fudge [<time>]", NULLCHAR,
"kick", dokicks, 2, "nntp kick <name|abbr>", NULLCHAR,
"listserver", dolists, 0, NULLCHAR, NULLCHAR,
"stop", dostop, 0, "nntp stop <name|abbr>", NULLCHAR,
"trace", donntptrace, 0, NULLCHAR, NULLCHAR,
NULLCHAR,
};
int donntp(int argc, char **argv)
{
return subcmd(nntpcmds,argc,argv);
}
static int donntptrace(int argc, char **argv)
{
if (argc < 2)
cwprintf(NULL, "%d\r\n", nntptrace);
else
nntptrace = atoi(argv[1]);
return 0;
}
static int dofudge(int argc, char *argv[])
{
if (argc < 2)
{
cwprintf(NULL, "NNTP - Fudge factor %d\n", fudge);
}
else
{
fudge = abs(atoi(argv[1]));
}
return 0;
}
static int dobatch(int argc, char *argv[])
{
if (argc < 2)
{
cwprintf(NULL, "NNTP - Batch %d\n", batch);
}
else if (atoi(argv[1]) > 0 && atoi(argv[1]) < BATCH_MAX)
{
fudge = abs(atoi(argv[1]));
}
return 0;
}
static int dodirect(int argc, char *argv[])
{
if (argc < 2)
{
cwprintf(NULL, "NNTP - direct %s\n", direct ? "on" : "off");
}
else if (stricmp(argv[1], "on") == 0)
{
direct = TRUE;
}
else
{
direct = FALSE;
}
return 0;
}
static int dodups(int argc, char *argv[])
{
int loop;
if (argc < 2)
{
cwprintf(NULL, "%s\n", duptab[dup_method]);
}
else
{
for (loop = 0; loop < 3; loop++)
{
if (strnicmp(argv[1], duptab[loop], MIN(strlen(argv[1]), strlen(duptab[loop]))) == NULL)
break;
}
if (loop == 3)
loop = 0;
dup_method = loop;
}
return 0;
}
static int doadds(int argc, char *argv[])
{
BOOL auto_fail = FALSE;
char buffer[256];
struct nntpservers *np;
for(np = Nntpservers; np != NULLNNTP; np = np->next)
if (stricmp(np->name, argv[1]) == 0)
break;
if (np == NULLNNTP)
{
np = (struct nntpservers *) calloc(1, sizeof(struct nntpservers));
np->name = strdup(argv[1]);
np->abbr = strdup(argv[3]);
np->ipdest = resolve(argv[1]);
np->next = Nntpservers;
Nntpservers = np;
np->lowtime = np->hightime = -1;
np->nntpcli_t.func = nntptick; /* what to call on timeout */
np->nntpcli_t.arg = (void *)np;
np->state = NN_RDY;
np->stage = NN_OPEN;
np->input0 = NULL;
np->input1 = NULL;
np->output = NULL;
np->got_table = NULL;
np->RS_Hist = FALSE;
np->dup_method = dup_method;
if (dup_method == 0 || dup_method == 1)
{
sprintf(buffer, "<ReadBack$Dir>.%sMail", np->abbr);
if (np->id_file = fopen(buffer, "r"), np->id_file != NULL)
{
fclose(np->id_file);
np->id_file = NULL;
np->RS_Hist = TRUE;
}
else
{
auto_fail = TRUE;
}
}
if ((dup_method == 0 && auto_fail) || dup_method == 2)
{
sprintf(buffer, "<NNTP$Dir>.%sHist", np->abbr);
if (np->id_file = fopen(buffer, "r"), np->id_file == NULL)
{
np->id_file = fopen(buffer, "w");
}
fclose(np->id_file);
np->id_file = NULL;
np->RS_Hist = FALSE;
}
make_got_table(0, (void *)np);
}
if (argc > 4)
{
int i;
for (i = 4; i < argc; ++i)
{
if (isdigit(*argv[i]))
{
int lh, ll, hh, hl;
sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
np->lowtime = lh * 100 + ll;
np->hightime = hh * 100 + hl;
}
}
}
/* set timer duration */
set_timer(&(np->nntpcli_t), atol(argv[2]) * 1000L);
start_timer(&(np->nntpcli_t));
return 0;
}
static int dodrops(int argc, char *argv[])
{
struct nntpservers *np, *npprev = NULLNNTP;
for(np = Nntpservers; np != NULLNNTP; npprev = np, np = np->next)
{
if (stricmp(np->name, argv[1]) == 0 || stricmp(np->abbr, argv[1]) == 0)
{
stop_timer(&np->nntpcli_t);
free(np->name);
free(np->abbr);
if (np->input1 != NULL)
fclose(np->input1);
if (np->input0 != NULL)
fclose(np->input0);
if (np->output != NULL)
fclose(np->output);
if (np->got_table != NULL)
{
flex_free((flex_ptr) &(np->got_table));
np->got_table = NULL;
np->msg_tot = 0;
}
if(npprev != NULLNNTP)
npprev->next = np->next;
else
Nntpservers = np->next;
free((char *)np);
return 0;
}
}
cwprintf(NULL, "NNTP - No such server enabled.\r\n");
return 0;
}
static int dokicks(int argc, char *argv[])
{
struct nntpservers *np;
for (np = Nntpservers; np != NULLNNTP; np = np->next)
{
if (stricmp(np->name, argv[1]) == 0 || stricmp(np->abbr, argv[1]) == 0)
{
/* If the timer is not running, the timeout function has
already been called and we don't want to call it again. */
if (run_timer(&np->nntpcli_t))
{
np->state = NN_CMD;
np->stage = NN_OPEN;
stop_timer(&np->nntpcli_t);
nntptick((void *)np);
}
else
{
cwprintf(NULL, "NNTP - Can't restart\r\n");
}
return 0;
}
}
cwprintf(NULL, "NNTP - No such server enabled.\r\n");
return 0;
}
static int dostop(int argc, char *argv[])
{
struct nntpservers *np;
for(np = Nntpservers; np != NULLNNTP; np = np->next)
{
if (stricmp(np->name, argv[1]) == 0 || stricmp(np->abbr, argv[1]) == 0)
{
quit(np, FALSE);
start_timer(&np->nntpcli_t);
return 0;
}
}
cwprintf(NULL, "NNTP - No such server enabled.\r\n");
return 0;
}
static struct directory *make_dir(char *dir)
{
struct directory *list=NULL, *entry;
char name[256];
for (filedir(dir, 0, name); *name; filedir(dir, 1, name))
{
if (entry = malloc(sizeof(struct directory)), entry == 0)
break;
entry->name = strdup(name);
entry->next = list;
list = entry;
}
return list;
}
static void kill_dir(struct directory *dir)
{
struct directory *entry;
for (entry = dir; entry; )
{
dir = entry->next;
free(entry->name);
free(entry);
entry = dir;
}
}
static int id_sort(const void *obj1, const void *obj2)
{
return(strcmp((char *) obj1, (char *) obj2));
}
static void make_got_table(int at, void *handle)
{
char buffer[256];
int loop;
message_data temp;
struct nntpservers *cb;
at = at;
cb = (struct nntpservers *) handle;
if (cb->got_table == NULL)
{
cb->msg_tot = 0;
if (!flex_alloc((flex_ptr) &(cb->got_table), ID_LEN * 21))
return;
}
if (cb->id_file == NULL)
{
if (cb->RS_Hist)
{
sprintf(buffer, "<ReadBack$Dir>.%sMail", cb->abbr);
if (cb->id_file = fopen(buffer, "r"), cb->id_file != NULL)
{
fseek(cb->id_file, 0, SEEK_END);
cb->file_len = ftell(cb->id_file);
fseek(cb->id_file, 9, SEEK_SET);
}
}
else if (cb->dup_method != 1)
{
sprintf(buffer, "<NNTP$Dir>.%sHist", cb->abbr);
if (cb->id_file = fopen(buffer, "r+"), cb->id_file != NULL)
{
fseek(cb->id_file, 0, SEEK_END);
cb->file_len = ftell(cb->id_file);
fseek(cb->id_file, 0, SEEK_SET);
}
}
}
if (cb->id_file && ftell(cb->id_file) < cb->file_len)
{
if (flex_extend((flex_ptr) &(cb->got_table), (cb->msg_tot + 21) * ID_LEN))
{
for (loop = 0; loop < 20 && ftell(cb->id_file) < cb->file_len; loop++)
{
if (cb->RS_Hist)
{
fread(&temp, sizeof(message_data), 1, cb->id_file);
fgets(buffer, 250, cb->id_file);
}
fgets(buffer, 250, cb->id_file);
strncpy((cb->got_table)[cb->msg_tot], (buffer[0] == '<' ? &buffer[1] : buffer), ID_LEN);
(cb->got_table)[cb->msg_tot][ID_LEN - 1] = '\0';
rip((cb->got_table)[cb->msg_tot]);
if (cb->RS_Hist)
fseek(cb->id_file, temp.comp_bytes + 4L, SEEK_CUR);
cb->msg_tot++;
}
qsort(cb->got_table, cb->msg_tot, ID_LEN, id_sort);
}
else
{
if (nntptrace)
cwprintf(NULL, "NNTP - No room for dup check table\r\n");
}
}
else
{
if (cb->RS_Hist && cb->id_file)
{
fclose(cb->id_file);
cb->id_file = NULL;
}
if (nntptrace > 2)
cwprintf(NULL, "NNTP - Loaded %d IDs\r\n", cb->msg_tot);
return;
}
alarm_set(alarm_timenow() + 2, make_got_table, (void *)cb);
}
static void nntptick(void *tp)
{
char title[256];
struct socket lsocket, fsocket;
register struct nntpservers *cb;
cb = (struct nntpservers *) tp;
if (cb == NULL)
return;
if (cb->state != NN_CMD)
return;
sprintf(title, "NNTP - %s", cb->name);
cb->window = Window_Open(NULL, title, term_NO_INPUT | term_DONT_DESTROY);
/* setup the socket */
fsocket.address = cb->ipdest;
fsocket.port = NNTP_PORT;
lsocket.address = ip_addr; /* our ip address */
lsocket.port = lport++; /* next unused port */
if (nntptrace)
{
cwprintf(cb->window, "NNTP daemon entered\r\n",inet_ntoa(fsocket.address));
}
if (nntptrace > 1)
{
cwprintf(cb->window, "NNTP trying Connection to %s\r\n",inet_ntoa(fsocket.address));
}
stop_timer(&cb->nntpcli_t);
cb->batch = 0;
cb->now[0] = 3;
os_word(14, cb->now);
time_adj(cb->now, -(fudge));
if (cb->RS_Hist == FALSE)
{
long offset;
if (cb->id_file == NULL)
{
sprintf(title, "<NNTP$Dir>.%sHist", cb->abbr);
cb->id_file = fopen(title, "a+");
offset = 0;
}
else
{
offset = ftell(cb->id_file);
}
fseek(cb->id_file, 0, SEEK_END);
cb->file_len = ftell(cb->id_file);
os_swi4(OS_ConvertDateAndTime, (int) cb->now, (int) title, 30, (int) "%YR%MN%DY %24%MI%SE");
fprintf(cb->id_file, "# %s\n", title);
fseek(cb->id_file, offset, SEEK_SET);
}
/* open nntp connection */
cb->stage = NN_OPEN; /* init stage placeholder */
cb->state = NN_CMD; /* init state placeholder */
cb->tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, tcp_window, (void(*)())nntp_rec, (void(*)())nntp_cts, (void(*)())nntp_state, 0, (char *)cb);
cb->tcb->user = (char *)cb; /* Upward pointer */
}
static BOOL have_we(char *line, struct nntpservers *cb)
{
BOOL gotmem = TRUE;
char buffer[LINELEN];
rip(line);
strcpy(buffer, &line[1]);
buffer[ID_LEN - 1] = '\0';
if (bsearch(buffer, cb->got_table, cb->msg_tot, ID_LEN, id_sort) != NULL)
{
if (nntptrace > 2)
cwprintf(cb->window, "NNTP - Already got %s\r\n", line);
return(TRUE);
}
if (cb->msg_tot % 20 == 0)
gotmem = flex_extend((flex_ptr) &(cb->got_table), (cb->msg_tot + 21) * ID_LEN);
if (gotmem)
{
strncpy((cb->got_table)[cb->msg_tot], buffer, ID_LEN);
(cb->got_table)[cb->msg_tot][ID_LEN - 1] = '\0';
rip((cb->got_table)[cb->msg_tot]);
cb->msg_tot++;
qsort(cb->got_table, cb->msg_tot, ID_LEN, id_sort);
}
if (cb->RS_Hist == FALSE && cb->id_file)
{
long offset = ftell(cb->id_file);
fseek(cb->id_file, 0, SEEK_END);
fprintf(cb->id_file, "%s\n", line);
fseek(cb->id_file, offset, SEEK_SET);
}
return(FALSE);
}
BOOL nntp_select(struct nntpservers *cb)
{
BOOL ret = FALSE;
char buffer[256];
if( !cb->input0 )
{
sprintf(buffer, "<NNTP$Dir>.%sNGroup", cb->abbr);
cb->input0 = fopen(buffer, "rb+");
}
if (cb->input0)
{
if (fgets(buffer, LINELEN - 1, cb->input0) != 0 && strlen(buffer) > 12)
{
strtok(buffer, " \n");
cb->lastread = atoi(strtok(NULL, " \n"));
if (nntptrace > 1)
{
cwprintf(cb->window, "NNTP - Selecting group %s\r\n", buffer);
}
rip(buffer);
sendit(cb,"GROUP %s\r\n", buffer);
cb->stage = NN_SELG;
cb->state = NN_CMD;
ret = TRUE;
}
else
{
fclose(cb->input0);
cb->input0 = NULL;
cb->stage = NN_QUIT;
cb->state = NN_RDY;
}
}
return(ret);
}
static BOOL nntp_getnews(register struct nntpservers *cb)
{
BOOL ret = FALSE;
char buffer[256], line[NNTPMAXLEN + 1];
if (cb->input1 == NULL && cb->batch == 0)
{
sprintf(buffer, "<NNTP$Dir>.%sNew", cb->abbr);
cb->input1 = fopen(buffer, "r");
}
if (cb->input1 != NULL)
{
while (cb->batch < batch && cb->input1 != NULL && !feof(cb->input1))
{
while(fgets(line, LINELEN - 1, cb->input1) != NULL && have_we(line, cb))
;
if (feof(cb->input1))
{
fclose(cb->input1);
cb->input1 = NULL;
sprintf(buffer, "<NNTP$Dir>.%sNew", cb->abbr);
remove(buffer);
}
else
{
rip(line);
sendit(cb, "ARTICLE %s\r\n", line);
cb->stage = NN_GETN;
cb->state = NN_CMD;
(cb->batch)++;
if (nntptrace > 2)
{
cwprintf(cb->window, "NNTP - Asking for article %s\r\n", line);
}
}
}
}
if (cb->batch > 0)
{
cb->stage = NN_GETN;
cb->state = NN_CMD;
ret = TRUE;
}
else
{
cb->stage = NN_NEWN;
cb->state = NN_RDY;
ret = FALSE;
}
return(ret);
}
static BOOL nntp_newnews(register struct nntpservers *cb)
{
BOOL ret = FALSE;
char buffer[256], line[NNTPMAXLEN + 1];
if (cb->input0 == NULL)
{
sprintf(buffer, "<NNTP$Dir>.%sGroup", cb->abbr);
cb->input0 = fopen(buffer, "r");
}
if (cb->input0 != NULL)
{
if (fgets(line, NNTPMAXLEN - 25, cb->input0) != NULL && isalpha(*line))
{
rip(line);
sendit(cb, "NEWNEWS %s %s %s GMT\r\n", line, cb->date, cb->hour);
cb->stage = NN_NEWN;
cb->state = NN_CMD;
if (nntptrace > 1)
cwprintf(cb->window, "NNTP - Checking group %s\r\n", line);
ret = TRUE;
}
else
{
FILE *temp;
fclose(cb->input0);
cb->input0 = NULL;
sprintf(buffer, "<NNTP$Dir>.%sLast", cb->abbr);
if (temp = fopen(buffer, "w"), temp != NULL)
{
os_swi4(OS_ConvertDateAndTime, (int) cb->now, (int) cb->date, 10, (int) "%YR%MN%DY");
os_swi4(OS_ConvertDateAndTime, (int) cb->now, (int) cb->hour, 10, (int) "%24%MI%SE");
fprintf(temp, "%s\n%s\n", cb->date, cb->hour);
fclose(temp);
ret = FALSE;
}
cb->state = NN_RDY;
cb->stage = NN_QUIT /* NN_BYNUM */;
}
}
else
{
cb->state = NN_RDY;
cb->stage = NN_QUIT /* NN_BYNUM */;
}
return(ret);
}
static BOOL nntp_newgroups(register struct nntpservers *cb)
{
BOOL ret = FALSE;
char buffer[256];
FILE *temp;
sprintf(buffer, "<NNTP$Dir>.%sLast", cb->abbr);
if (temp = fopen(buffer, "r"), temp != NULL)
{
if (fgets(cb->date, 8, temp) == NULL)
os_swi4(OS_ConvertDateAndTime, (int) cb->now, (int) cb->date, 10, (int) "%YR%MN%DY");
if (fgets(cb->hour, 8, temp) == NULL)
strcpy(cb->hour, "000001");
fclose(temp);
}
else
{
os_swi4(OS_ConvertDateAndTime, (int) cb->now, (int) cb->date, 10, (int) "%YR%MN%DY");
strcpy(cb->hour, "000001");
}
rip(cb->date);
rip(cb->hour);
sendit(cb, "NEWGROUPS %s %s GMT\r\n", cb->date, cb->hour);
ret = TRUE;
if (nntptrace > 1)
cwprintf(cb->window, "NNTP - Checking for new groups since last call\r\n");
return(ret);
}
static BOOL nntp_next_command(register struct nntpservers *cb)
{
BOOL ret = FALSE;
switch(cb->stage)
{
case NN_POST:
sendit(cb, "POST\r\n");
cb->state = NN_CMD;
cb->stage = NN_POST;
ret = TRUE;
break;
case NN_NEWG:
if (nntp_newgroups(cb))
{
cb->state = NN_CMD;
ret = TRUE;
}
else
{
cb->state = NN_RDY;
cb->stage = NN_NEWN;
ret = FALSE;
}
break;
case NN_NEWN:
if (nntp_newnews(cb))
{
cb->state = NN_CMD;
ret = TRUE;
}
else
{
cb->state = NN_RDY;
cb->stage = NN_QUIT /* NN_SELG */;
ret = FALSE;
}
break;
case NN_GETN:
if (nntp_getnews(cb))
{
cb->state = NN_CMD;
ret = TRUE;
}
else
{
cb->state = NN_RDY;
cb->stage = NN_NEWN;
ret = FALSE;
}
break;
case NN_SELG:
if (nntp_select(cb))
{
cb->state = NN_CMD;
ret = TRUE;
}
else
{
cb->state = NN_RDY;
cb->stage = NN_QUIT;
ret = FALSE;
}
break;
default:
quit(cb, TRUE);
ret = TRUE;
break;
}
return(ret);
}
static void save_news(register struct nntpservers *cb)
{
if (direct)
{
char buffer[256];
FILE *out;
long item_len;
sprintf(buffer, "<Mail$Dir>.Folder.%sNews", cb->abbr);
out = fopen(buffer, "r+");
fseek(out, 0, SEEK_END);
item_len = ftell(out);
fseek(out, cb->rnewspos, SEEK_SET);
fprintf(out, "#! rnews %07ld\n", item_len - cb->rnewspos - 17L);
fseek(out, 0, SEEK_END);
fclose(out);
}
else
{
char line[NNTPMAXLEN + 1], buffer[256];
FILE *temp, *out;
long item_len;
sprintf(buffer, "<Mail$Dir>.Folder.%sNews", cb->abbr);
temp = fopen(cb->temp, "r");
fseek(temp, 0, SEEK_END);
if (item_len = ftell(temp), item_len > 0)
{
out = fopen(buffer, "a");
fprintf(out, "#! rnews %d\n", (int) item_len);
fseek(temp, 0, SEEK_SET);
while (fgets(line, NNTPMAXLEN, temp))
fputs(line, out);
fclose(out);
}
fclose(temp);
remove(cb->temp);
free(cb->temp);
cb->temp = NULL;
}
if (cb->batch > 0)
{
(cb->batch)--;
}
}
static void nntp_post(register struct nntpservers *cb)
{
char buffer[256], line[84];
FILE *temp;
if (nntptrace > 1)
cwprintf(cb->window, "NNTP - sending article %s\r\n", cb->topost->name );
sprintf( buffer, "%s.articles.%s", newsqueue, cb->topost->name );
if (temp = fopen(buffer, "r"), temp == NULL)
{
if (nntptrace > 1)
cwprintf(cb->window, "NNTP - strange, article file rejects to be opened\r\n" );
sendit(cb, ".\r\n");
return;
}
while (fgets(line, 81, temp))
{
rip(line);
if (line[0] == '.')
sendit(cb, ".");
sendit(cb, "%s\r\n", line);
}
sendit(cb, ".\r\n");
fclose(temp);
remove(buffer);
}
void nntp_transaction(register struct nntpservers *cb)
{
if (nntptrace > 4)
cwprintf(cb->window, "nntp_transaction() enter state=%u stage=%u\r\n", cb->state, cb->stage);
if (nntptrace > 3)
{
cwprintf(cb->window, "%s\r\n",cb->buf);
}
if (cb->state == NN_DAT)
{
tcp_output(cb->tcb); /* Send ACK; disk I/O is slow */
if (cb->buf[0] == '.' && cb->buf[1] == '\n' && cb->buf[2] == '\0')
{
cb->state = NN_RDY;
if (cb->output != NULL)
{
fclose(cb->output);
cb->output = NULL;
}
switch(cb->stage)
{
case NN_NEWG:
cb->stage = NN_NEWN;
break;
case NN_NEWN:
cb->stage = NN_GETN;
cb->batch = 0;
break;
case NN_GETN:
case NN_GNUM:
save_news(cb);
break;
case NN_SELG:
cb->stage = NN_SELG;
break;
}
}
else
{
BOOL dots;
/* Append to data file */
dots = (strncmp(cb->buf, "..", 2) == 0);
if (cb->output != NULL)
{
if (fprintf(cb->output, "%s", &cb->buf[dots]) < 0)
{
cb->state = NN_RDY;
tprintf(cb->tcb, "File write error\n");
}
}
}
}
if (cb->state == NN_CMD)
{
char buffer[256];
struct directory *next;
if (nntptrace > 2)
cwprintf(cb->window, "%s\n", cb->buf);
switch(cb->stage)
{
case NN_OPEN:
switch(atoi(cb->buf))
{
case 200:
sprintf(buffer, "%s.articles", newsqueue);
if (cb->topost = make_dir(buffer), cb->topost != NULL)
cb->stage = NN_POST;
else
cb->stage = NN_NEWG;
cb->state = NN_RDY;
break;
case 201:
cb->stage = NN_NEWG;
cb->state = NN_RDY;
break;
default:
cb->stage = NN_QUIT;
cb->state = NN_RDY;
break;
}
break;
case NN_POST:
switch(atoi(cb->buf))
{
case 240:
sprintf(buffer, "%s.badmarker.%s", newsqueue, cb->topost->name);
remove(buffer);
next = cb->topost->next;
free(cb->topost->name);
free(cb->topost);
cb->topost = next;
if (cb->topost != NULL)
cb->stage = NN_POST;
else
cb->stage = NN_NEWG;
cb->state = NN_RDY;
break;
case 340:
nntp_post(cb);
cb->stage = NN_POST;
cb->state = NN_CMD;
break;
default:
kill_dir(cb->topost);
cb->stage = NN_NEWG;
cb->state = NN_RDY;
break;
}
break;
case NN_NEWG:
switch(atoi(cb->buf))
{
case 231:
if (cb->output)
fclose(cb->output);
sprintf(buffer, "<Mail$Dir>.Folder.%sNG", cb->abbr);
if (cb->output = fopen(buffer, "a"), cb->output != NULL)
{
cb->stage = NN_NEWG;
cb->state = NN_DAT;
}
else
{
cb->stage = NN_NEWN;
cb->state = NN_RDY;
}
break;
default:
cb->stage = NN_NEWN;
cb->state = NN_RDY;
break;
}
break;
case NN_NEWN:
switch(atoi(cb->buf))
{
case 230:
if (cb->output)
fclose(cb->output);
sprintf(buffer, "<NNTP$Dir>.%sNew", cb->abbr);
if (cb->output = fopen(buffer, "w"), cb->output != NULL)
{
cb->stage = NN_NEWN;
cb->state = NN_DAT;
}
else
{
cb->stage = NN_BYNUM;
cb->state = NN_RDY;
}
break;
}
break;
case NN_GETN:
case NN_GNUM:
switch(atoi(cb->buf))
{
case 220:
if (cb->output)
fclose(cb->output);
if (cb->temp)
{
free(cb->temp);
cb->temp = NULL;
}
if (direct)
{
char buffer[256];
sprintf(buffer, "<Mail$Dir>.Folder.%sNews", cb->abbr);
if (cb->output = fopen(buffer, "a"), cb->output != NULL)
{
cb->state = NN_DAT;
fseek(cb->output, 0, SEEK_END);
cb->rnewspos = ftell(cb->output);
fprintf(cb->output, "#! rnews %07d\n", 0);
}
else
{
cb->state = NN_RDY;
cb->batch--;
}
}
else
{
cb->temp = strdup(tmpnam(NULL));
if (cb->output = fopen(cb->temp, "w"), cb->output != NULL)
{
cb->state = NN_DAT;
}
else
{
cb->state = NN_RDY;
cb->batch--;
}
}
break;
case 430:
case 423:
cb->state = NN_RDY;
cb->batch--;
break;
default:
if (cb->stage == NN_GETN)
cb->stage = NN_SELG;
else
cb->stage = NN_QUIT;
cb->state = NN_RDY;
break;
}
break;
case NN_SELG:
switch(atoi(cb->buf))
{
case 211:
cb->stage = NN_SELG;
cb->state = NN_RDY;
break;
default:
cb->stage = NN_SELG;
cb->state = NN_RDY;
break;
}
break;
}
}
if (cb->state == NN_RDY)
{
while (!nntp_next_command(cb))
;
}
}
static void close_down(struct nntpservers *cb, BOOL normal)
{
if (cb->input1 != NULL)
fclose(cb->input1);
if (cb->input0 != NULL)
fclose(cb->input0);
if (cb->output != NULL)
fclose(cb->output);
if (cb->id_file != NULL)
fclose(cb->id_file);
if (cb->temp != NULL)
{
/* remove(cb->temp); */
free(cb->temp);
cb->temp = NULL;
}
cb->input1 = NULL;
cb->input0 = NULL;
cb->output = NULL;
cb->id_file = NULL;
if (cb->window)
{
cb->window->Attr = ATTR_REVERSE;
cb->window->Flags.flags.dont_destroy = FALSE;
if (normal)
Window_Close(cb->window);
else
cwprintf(cb->window, "\nThis session has finished, please close the window\n");
cb->window = NULL;
}
start_timer(&cb->nntpcli_t);
}
/* close down link after a failure */
static void quit(struct nntpservers *cb, BOOL normal)
{
cb->state = NN_RDY;
sendit(cb, quitcmd); /* issue a quit command */
close_tcp(cb->tcb); /* close up connection */
if (nntptrace)
{
cwprintf(cb->window, "NNTP Closing down (%s)\r\n", normal ? "Normal" : "Error");
if (!normal && cb->buf && cb->buf[0])
cwprintf(cb->window, "NNTP Error - %s\r\n", cb->buf);
}
close_down(cb, normal);
}
/* nntp receiver upcall routine. fires up the state machine to parse input */
static void nntp_rec(struct tcb *tcb, int16 cnt)
{
register struct nntpservers *cb;
char c;
struct mbuf *bp;
if ((cb = (struct nntpservers *) tcb->user) == NULL) /* point to our struct */
{
close_tcp(tcb);
return;
}
if (nntptrace > 4)
cwprintf(cb->window, "nntp_rec called\r\n");
recv_tcp(tcb, &bp, cnt); /* suck up chars from low level routine */
/* Assemble input line in buffer, return if incomplete */
while(pullone(&bp,&c) == 1)
{
switch(c)
{
case '\r': /* strip cr's */
continue;
case '\n': /* line is finished, go do it! */
cb->buf[cb->cnt++] = '\n';
cb->buf[cb->cnt] = '\0';
nntp_transaction(cb);
cb->cnt = 0;
break;
default: /* other chars get added to buffer */
cb->buf[cb->cnt++] = c;
if(cb->cnt > LINELEN - 2)
{
cb->buf[cb->cnt] = '\0';
nntp_transaction(cb);
cb->cnt = 0;
}
break;
}
}
}
/* nntp transmitter ready upcall routine. twiddles cts flag */
static void nntp_cts(struct tcb *tcb, int16 cnt)
{
register struct nntpservers *cb;
cb = (struct nntpservers *)tcb->user; /* point to our struct */
if (nntptrace > 4)
{
cwprintf(cb->window, "nntp_cts called avail %d\r\n", cnt);
}
/* don't do anything until/unless we're supposed to be sending */
if(cb->cts == 0)
return;
}
/* nntp state change upcall routine. */
static void nntp_state(register struct tcb *tcb, char old, char new)
{
register struct nntpservers *cb;
extern char *tcpstates[];
old = old;
cb = (struct nntpservers *)tcb->user;
if (nntptrace > 4)
cwprintf(cb->window, "nntp_state called: %s\r\n",tcpstates[new]);
switch(new)
{
case ESTABLISHED:
cb->state = NN_CMD;
cb->stage = NN_OPEN;
cb->cnt = 0;
break;
case CLOSE_WAIT:
close_tcp(tcb); /* shut things down */
break;
case CLOSED:
/* if this close was not done by us ie. a RST */
cwprintf(cb->window, "NNTP Closed\r\n");
close_down(cb, FALSE);
del_tcp(tcb);
cb->state = NN_CMD;
cb->stage = NN_OPEN;
break;
}
}
/* Send message back to server */
static void sendit(struct nntpservers *cb, char *fmt, ...)
{
va_list argptr;
struct mbuf *bp;
char tmpstring[256];
va_start(argptr,fmt);
vsprintf(tmpstring,fmt,argptr);
va_end(argptr);
if (nntptrace > 3)
{
cwprintf(cb->window, ">>> %s\r\n", tmpstring);
}
bp = qdata(tmpstring, strlen(tmpstring));
send_tcp(cb->tcb, bp);
}
static int dolists(int argc, char *argv[])
{
struct nntpservers *np;
for (np = Nntpservers; np != NULLNNTP; np = np->next)
{
char tbuf[80];
if (np->lowtime != -1 && np->hightime != -1)
sprintf(tbuf, " -- %02d:%02d-%02d:%02d", np->lowtime/100, np->lowtime%100, np->hightime/100, np->hightime%100);
else
tbuf[0] = '\0';
cwprintf(NULL, "%-32s (%lu/%lu%s)\r\n", np->name,
read_timer(&np->nntpcli_t) /1000L,
dur_timer(&np->nntpcli_t) /1000L,
tbuf);
}
return 0;
}